home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Shareware / Comunicatii / jaeger / jaeger.exe / {app} / Tools / ToolPublishBlogroll.py < prev    next >
Text File  |  2004-04-06  |  11KB  |  417 lines

  1. #!/bin/python
  2. # -*- coding: iso-8859-1 -*-
  3.  
  4. """
  5. ToolPublishBlogroll.py
  6.  
  7. David Janes
  8. BlogMatrix
  9. 2004.02.15
  10. """
  11.  
  12. import sys
  13. import urllib
  14. import Tool
  15. import cStringIO
  16.  
  17. templates = {
  18.     "blogroll" : """\
  19. <div class="blogroll">
  20. #for $category in $categories
  21. <div class="sidetitle">$category</div>
  22. <div class="side">
  23. #for $blog in $blogs
  24. #if $blog.category == $category
  25. <a href="$escape_html($blog.url)">$escape_html($blog.title)</a>
  26. <br/>
  27. #end if 
  28. #end for
  29. </div>
  30. #end for
  31. </div>
  32. """,
  33.     "opml" : """\
  34. <?xml version="1.0" encoding="ISO-8859-1"?>
  35. <opml version="1.0">
  36. <head>
  37.     <title>OPML Blogroll</title>
  38.     <ownerName>Generated from BlogMatrix JΣger</ownerName>
  39. </head>
  40. <body>
  41.  <outline title="Blogroll">
  42. #for $category in $categories
  43.   <outline title=$quote_attribute($category)>
  44. #for $blog in $blogs
  45. #if $blog.category == $category
  46.     <outline 
  47.       title=$quote_attribute($blog.title)
  48.       url=$quote_attribute($blog.url)
  49. #if $blog.syndication_url
  50.       rssUrl=$quote_attribute($blog.syndication_url)
  51. #end if
  52.     />
  53. #end if
  54. #end for
  55.   </outline>
  56. #end for
  57.  </outline>
  58. </body>
  59. </opml>
  60. """
  61. }
  62.  
  63. class ToolPublishBlogroll(Tool.ToolInterface):
  64.     """
  65.     The interface for your tool. Simply create an instance of this object and Jaeger
  66.     will figure it out.
  67.     """
  68.     def __init__(self):
  69.         Tool.ToolInterface.__init__(self, self.WEBSERVER)
  70.         
  71.     def get_label(self, selected):
  72.         return    "Publish Blogroll"
  73.         
  74.     def get_server(self, path):
  75.         """
  76.         """
  77.         return    {
  78.             "/": ( self.serve_root, "" ),
  79.             "/htmlftp": ( self.serve_htmlftp, "Publish as HTML to an FTP location" ),
  80.             "/opmlftp": ( self.serve_opmlftp, "Publish as OPML to an FTP location" ),
  81.         }.get(path)
  82.         
  83.     def serve_root(self, operations, path, valuemap):
  84.         result = [
  85.             self.text_standard_header(path),
  86.             """
  87. <h2>Publish Blogroll</h2>
  88. <p class="first">
  89. This extension lets you publish your blogroll (i.e. all the weblogs you
  90. are following) to several well known-blogging tools.
  91.  
  92. <ul>
  93. <li>
  94. <a href="htmlftp">Publish as HTML to an FTP location</a>
  95. (use this for MovableType)
  96.  
  97. <li>
  98. <a href="opmlftp">Publish as OPML to an FTP location</a>
  99.  
  100. <li>
  101. <i>More coming...</i>
  102. <!--
  103. <li>
  104. <a href="blogger">Publish to Blogger</a>
  105.  
  106. <li>
  107. <a href="blogrolling">Publish to Blogrolling.com</a>
  108. -->
  109. </ul>
  110. """,
  111.             self.text_standard_footer()
  112.         ]
  113.         return    200, "text/html", None, result
  114.  
  115.     def serve_htmlftp(self, operations, path, valuemap):
  116.         return    self.serve_underlying(operations, path, valuemap,
  117.             template_key = "blogroll",
  118.             page_title = "Publish as HTML to an FTP server"
  119.             )
  120.         
  121.     def serve_opmlftp(self, operations, path, valuemap):
  122.         return    self.serve_underlying(operations, path, valuemap,
  123.             template_key = "opml",
  124.             page_title = "Publish as OPML to an FTP server"
  125.             )
  126.         
  127.     def serve_underlying(self, operations, path, valuemap, template_key, page_title):
  128.         is_form = valuemap.get("_form")
  129.  
  130.         #
  131.         #    The 'name' and 'phone' values are persisted through the '*userdata' functions
  132.         #
  133.         hostname = valuemap.get("hostname")
  134.         if hostname == None:
  135.             hostname = operations.get_userdata("hostname_" + template_key, "")
  136.         else:
  137.             operations.set_userdata("hostname_" + template_key, hostname)
  138.  
  139.         username = valuemap.get("username")
  140.         if username == None:
  141.             username = operations.get_userdata("username_" + template_key, "")
  142.         else:
  143.             operations.set_userdata("username_" + template_key, username)
  144.  
  145.         password = valuemap.get("password")
  146.         if password == None:
  147.             password = operations.get_userdata("password_" + template_key, "")
  148.         else:
  149.             operations.set_userdata("password_" + template_key, password)
  150.  
  151.         file = valuemap.get("file")
  152.         if file == None:
  153.             file = operations.get_userdata("file_" + template_key, "")
  154.         else:
  155.             operations.set_userdata("file_" + template_key, file)
  156.  
  157.         startblogroll = valuemap.get("startblogroll")
  158.         if startblogroll == None:
  159.             startblogroll = operations.get_userdata("startblogroll_" + template_key, "<!-- START-BLOGROLL -->")
  160.         else:
  161.             operations.set_userdata("startblogroll_" + template_key, startblogroll)
  162.  
  163.         endblogroll = valuemap.get("endblogroll")
  164.         if endblogroll == None:
  165.             endblogroll = operations.get_userdata("endblogroll_" + template_key, "<!-- END-BLOGROLL -->")
  166.         else:
  167.             operations.set_userdata("endblogroll_" + template_key, endblogroll)
  168.             
  169.         submit = valuemap.get("submit")
  170.  
  171.         template = valuemap.get("template")
  172.         # print "template", template, dir(valuemap)
  173.         if not is_form:
  174.             template = operations.get_userdata("template_" + template_key, "")
  175.         else:
  176.             operations.set_userdata("template_" + template_key, template)
  177.  
  178.         delimeters = valuemap.get("delimeters", "")
  179.         if not is_form:
  180.             delimeters = operations.get_userdata("delimeters_" + template_key, "on")
  181.         else:
  182.             operations.set_userdata("delimeters_" + template_key, delimeters)
  183.  
  184.         # print "serve_htmlftp: B"
  185.         if not template: template = templates.get(template_key, "")
  186.  
  187.         # print "serve_htmlftp: C"
  188.         result = [
  189.             self.text_standard_header(path),
  190.             """<h2>%s</h2>""" % page_title
  191.         ]
  192.         
  193.         # print "serve_htmlftp: D"
  194.         template_result = ""
  195.         if True or submit in [ "Display Here", "Publish", "Publish Blogroll" ]:
  196.             try:
  197.                 from Cheetah.Template import Template
  198.  
  199.                 t = Template(template)
  200.                 
  201.                 #
  202.                 #    blogs are sorted by category, then by title
  203.                 #
  204.                 t.blogs = operations.get_weblogs()
  205.                 t.blogs.sort(lambda a, b: \
  206.                     cmp(a["category"].lower(), b["category"].lower()) or \
  207.                     cmp(a["title"].lower(), b["title"].lower()))
  208.  
  209.                 #
  210.                 #    we have to derive a list of the category names
  211.                 #
  212.                 t.categories = {}.fromkeys(map(lambda b : b["category"], t.blogs), 1).keys()
  213.                 t.categories.sort()
  214.                 
  215.                 #
  216.                 #    some useful functions for the template user
  217.                 #
  218.                 t.escape_html = self.escape_html
  219.                 t.quote_attribute = self.quote_attribute
  220.                 
  221.                 #
  222.                 #    generate the result
  223.                 #
  224.                 template_result = str(t)
  225.             except:
  226.                 traceback.print_exc(file = sys.stdout, limit = 2)
  227.                 
  228.         # print >> sys.stderr, "A", submit
  229.         if submit == "Publish Blogroll":
  230.             print >> sys.stderr, "ToolPublishBlogroll: called"
  231.             ftp = None
  232.             try:
  233.                 if not hostname: raise "'Hostname' is required"
  234.                 if not username: raise "'Username' is required"
  235.                 if not file: raise "'File' is required"
  236.                 if not startblogroll: raise "'Start Blogroll' is required"
  237.                 if not endblogroll: raise "'End Blogroll' is required"
  238.  
  239.                 import ftplib
  240.  
  241.                 ftp = ftplib.FTP()
  242.                 print >> sys.stderr, "ToolPublishBlogroll: connecting..."
  243.                 ftp.connect(hostname)
  244.  
  245.                 print >> sys.stderr, "ToolPublishBlogroll: logging in..."
  246.                 ftp.login(username, password)
  247.                 
  248.                 if not delimeters:
  249.                     to_upload = template_result
  250.                 else:
  251.                     print >> sys.stderr, "Getting current version of the file..."
  252.                     try:
  253.                         current_file = []
  254.                         def callback(block): current_file.append(block)
  255.  
  256.                         ftp.retrbinary("RETR %s" % file, callback)
  257.                         current_file = "".join(current_file)
  258.                     except:
  259.                         traceback.print_exc(file = sys.stdout, limit = 2)
  260.                         to_upload  = "\n".join([ startblogroll, template_result, endblogroll ])
  261.  
  262.                     if current_file:
  263.                         startx = current_file.find(startblogroll + "\n")
  264.                         if startx == -1: raise "Could not find 'Start Blogroll'"
  265.  
  266.                         endx = current_file.find(endblogroll, startx + 1)
  267.                         if endx == -1: raise "Could not find 'End Blogroll'"
  268.  
  269.                         to_upload = \
  270.                             current_file[:startx] + \
  271.                             startblogroll + "\n" + \
  272.                             template_result + \
  273.                             current_file[endx:]
  274.  
  275.                 sin = cStringIO.StringIO(to_upload)
  276.                 print >> sys.stderr, "ToolPublishBlogroll: uploading..."
  277.                 ftp.storbinary("STOR %s" % file, sin)
  278.  
  279.                 print >> sys.stderr, "ToolPublishBlogroll: closing..."
  280.                 ftp.quit()
  281.  
  282.                 result.append("""\
  283. <h3>OK</h3>
  284. <p class="first">
  285. The blogroll file was uploaded sucessfully.
  286. """)
  287.             except:
  288.                 try:
  289.                     if ftp: ftp.quit()
  290.                 except: pass
  291.  
  292.                 traceback.print_exc(file = sys.stdout, limit = 2)
  293.                 result.append("""\
  294. <h3>An error occured</h3>
  295. <p class="first">
  296. """ + self.escape_html(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[0]))
  297.  
  298.         result.append("""\
  299. <form method="POST">
  300. <h3>Login Information</h3>
  301. <p class="first">
  302. <table>
  303.  
  304. <tr>
  305. <td align="left" width=120>Host:</td>
  306. <td> </td>
  307. <td><input type="text" name="hostname" value=\"""" + self.escape_html(hostname) + """"></td>
  308. </tr>
  309.  
  310. <tr>
  311. <td align="left">User:</td>
  312. <td></td>
  313. <td><input type="text" name="username" value=\"""" + self.escape_html(username) + """"></td>
  314. </tr>
  315.  
  316. <tr>
  317. <td align="left">Password:</td>
  318. <td></td>
  319. <td><input type="password" name="password" value=\"""" + self.escape_html(password) + """"></td>
  320. </tr>
  321.  
  322. <tr>
  323. <td align="left">File:</td>
  324. <td></td>
  325. <td><input type="text" name="file" value=\"""" + self.escape_html(file) + """"></td>
  326. </tr>
  327.  
  328. <tr>
  329. <td></td>
  330. <td></td>
  331. <td><input type="Submit" name="submit" value="Publish Blogroll"></td>
  332. </tr>
  333. </table>
  334. """)
  335.  
  336.         result.append("""\
  337. <h3>Template</h3>
  338. <h4>Delimeters</h4>
  339. <p class="first">
  340. When publishing to a file and "Use Delimeters" is set, the strings "Start Blogroll" and 
  341. "End Blogroll" must be found in the file. All the text between these two markers
  342. will be replaced with the blogroll.
  343. If Use Delimeters isn't set, the file will be overwritten.
  344.  
  345. <p>
  346. <table>
  347. <tr>
  348. <td align="left" width=120>Start Blogroll:</td>
  349. <td> </td>
  350. <td><input type="text" size=60 name="startblogroll" value=\"""" + self.escape_html(startblogroll) + """"></td>
  351. </tr>
  352.  
  353. <tr>
  354. <td align="left">End Blogroll:</td>
  355. <td></td>
  356. <td><input type="text" size=60 name="endblogroll" value=\"""" + self.escape_html(endblogroll) + """"></td>
  357. </tr>
  358.  
  359. <tr>
  360. <td align="left">Use Delimeters:</td>
  361. <td></td>
  362. <td><input type="checkbox" name="delimeters" """ + ( delimeters and "checked" or "" ) + """></td>
  363. </tr>
  364.  
  365. </table>
  366.  
  367. <h4>Template</h4>
  368. <p class="first">
  369. The template language is <a href="http://www.cheetahtemplate.org/">Cheetah</a>.
  370. Documentation to follow on the <a href="http://jaeger.blogmatrix.com">blog</a>.
  371.  
  372. <p>
  373. <table>
  374. <tr>
  375. <td align="left" valign=top width=120>Template:</td>
  376. <td></td>
  377. <td><textarea rows=24 cols=50 name="template">""" + self.escape_html(template) + """</textarea></td>
  378. </tr>
  379.  
  380. <tr>
  381. <td></td>
  382. <td></td>
  383. <td>
  384. <input type="Submit" name="submit" value="Save all values">
  385. <!-- <input type="Submit" name="submit" value="Display Here"> -->
  386. </td>
  387. </tr>
  388. </table>
  389. </form>
  390. """)
  391.         
  392.         if True or submit == "Display Here":
  393.             result.append("""\
  394. <h3>Blogroll</h3>
  395. <pre class="first" style="background: #CCCCCC">""" + self.escape_html(template_result) + """</pre>""")
  396.  
  397.         result.append(self.text_standard_footer())            
  398.         return    200, "text/html", None, result
  399.  
  400.     def serve_cgi(self, operations, path, valuemap):
  401.         result = [
  402.             self.text_standard_header(path),
  403.             "<h4>Path</h4><p>%s" % path,
  404.             "<h4>Parameters</h4><p>",
  405.         ]
  406.         
  407.         for key, value in valuemap.iteritems():
  408.             result.append("%s: %s<br>" % ( key, value ))
  409.  
  410.         result.append(self.text_standard_footer())            
  411.         return    200, "text/html", None, result
  412.  
  413. #
  414. # creating it will register it
  415. #
  416. ToolPublishBlogroll()
  417.